package fr.mywiki.business.user;

import java.text.ParseException;

import javax.servlet.http.HttpServletRequest;

import fr.mywiki.business.account.AccountLite;
import fr.mywiki.business.login.LoginManager;
import fr.mywiki.model.ejbAdapter.EntityHomeCache;


/**
 * A user is either a account of the database, either an anonymous user, known by his ip.
 * 
 * @author tlombard
 */
public class User {
	/** Anonymous user known by his ip. */
	private static final int ANONYMOUS = 1;
	/** User known in the database and connected. */
	private static final int MEMBER = 2;
	
	/** The prefix displayed in the String representation in anonymous mode */ 
	public static String  ANONYMOUS_PREFIX = "[ip] ";
	/** The prefix displayed in the String representation in account mode */
	public static String  MEMBER_PREFIX = "[account] ";

	/** The mode of user represented by the object, ANONYMOUS or MEMBER. */
	private int mode;

	/** The ip of the user in case he is anonymous. */
	private String ip = null;
	/** If the user is a account of the database, he is identified by this object. */
	private AccountLite account = null;

	/**
	 * Constructs a <code>user</code> object from a <code>AccountLite</code> one. Connected mode.
	 * 
	 * @param account the account which will be the user.
	 */
	public User(AccountLite account) {
		mode = MEMBER;
		this.account = account;
	}

	/**
	 * <p>
	 * Constructs a <code>user</code> object from a <code>String</code> one. If <code>info</code>
	 * begins with <tt>[ip]</tt>, the object is considered in anonymous mode and the information
	 * is the ip address. If <code>info</code> begins with <tt>[account]</tt> then it is considered
	 * as a account mode and <code>account</code> is filled with the information.
	 * </p>
	 * <p>
	 * If there is no mode indicator in <code>ip</code>, then it is considered as an anonymous
	 * mode with an internet address.</p>
	 * 
	 * @param info the information on the user.
	 * @throws Exception if the info is not readable.
	 */
	public User(String info) throws Exception {
		try {
			if (info.startsWith(ANONYMOUS_PREFIX)) {
				mode = ANONYMOUS;
				ip = info.substring(ANONYMOUS_PREFIX.length());
			} else if (info.startsWith(MEMBER_PREFIX)) {
				mode = MEMBER;
				Long id = new Long(info.substring(MEMBER_PREFIX.length()));
				account = EntityHomeCache.getInstance().getAccountHome().findByPrimaryKey(id)
						.getAccountLite();
			} else throw new Exception("Unknown mode for User construction");
		} catch (ParseException e) {
			throw new Exception("Invalid information for User construction");
		}
	}

	/**
	 * <p>
	 * Constructs a <code>User</code> object from a <code>HttpServletRequest</code> one.
	 * </p>
	 * <p>
	 * First, the constructor tries to access the current user of the session linked to this
	 * request. If there is one, it creates a <code>User</code> from the connected Member.
	 * </p>
	 * <p>
	 * Otherwise, the remote address is retrieved and the object is built with the IP.
	 * </p>
	 * 
	 * @param request the current request
	 */
	public User(HttpServletRequest request) {
		AccountLite member = LoginManager.getLoggedUser(request.getSession());
		if (member == null) {
			mode = ANONYMOUS;
			ip = getIP(request);
		} else {
			mode = MEMBER;
			this.account = member;
		}
	}

	/**
	 * Returns a String object representing the <code>User</code> object. If <code>mode</code>
	 * is <code>ANONYMOUS</code>, the method returns <tt>[ip]</tt> followed by the ip of the
	 * user. Otherwise the method returns <tt>[account]</tt> followed by the identifier of the
	 * account in the database.
	 * 
	 * @return a <code>String</code> representation of the object.
	 * @see Object#toString()
	 */
	public String toString() {
		if (mode == ANONYMOUS)
			return ANONYMOUS_PREFIX + ip;
		return MEMBER_PREFIX + account.getId().toString();
	}

	/**
	 * Returns the IP remote address of a request.
	 * 
	 * @param request the request.
	 */
	private static String getIP(HttpServletRequest request) {
		return request.getRemoteAddr();
	}
	
	/**
	 * Returns true iif the user is an anonymous one.
	 * 
	 * @return a boolean
	 */
	public boolean isAnonymous() {
		return !isMember();
	}
	
	/**
	 * Returns true iif the user is a account.
	 * 
	 * @return a boolean
	 */
	public boolean isMember() {
		return mode == MEMBER;
	}
	
	/**
	 * Returns the AccountLite object if the user is a member, its ip otherwise.
	 * 
	 * @return either a <code>String</code> or a <code>AccountLite</code>
	 *         object.
	 */
	public Object getUserInfo() {
		if (isMember())
			return account;
		if (isAnonymous())
			return ip;
		return null;
	}
}
